package com.eastfair.imaster.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.annotation.base.LanguageTypeEnum;
import com.eastfair.annotation.base.SubjectTypeEnum;
import com.eastfair.api.QuestionnaireServiceFeign;
import com.eastfair.auth.api.UserAccountServiceFeign;
import com.eastfair.auth.dto.UserAccountDto;
import com.eastfair.auth.entity.UserAccount;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.cache.redis.RedisOps;
import com.eastfair.config.api.FormFieldServiceFeign;
import com.eastfair.config.api.SwitchServiceFeign;
import com.eastfair.config.dto.FormFieldCheckDTO;
import com.eastfair.config.dto.FormFieldDTO;
import com.eastfair.config.entity.Switch;
import com.eastfair.config.vo.FormFieldVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.RedisKeyConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.FaceIdentifyUtils;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.enums.AuditStateEnum;
import com.eastfair.enums.DisplayLocationEnum;
import com.eastfair.enums.SwitchEnum;
import com.eastfair.enums.SystemSourceEnum;
import com.eastfair.imaster.dao.VisitorRegisterMapper;
import com.eastfair.imaster.dto.VisitorRegisterDTO;
import com.eastfair.imaster.dto.VisitorRegisterStateDTO;
import com.eastfair.imaster.entity.VisitorRegister;
import com.eastfair.imaster.entity.VisitorRegisterException;
import com.eastfair.imaster.entity.VisitorRegisterState;
import com.eastfair.imaster.enumeration.VisitorRegisterStateRegisterTypeEnum;
import com.eastfair.imaster.service.*;
import com.eastfair.imaster.vo.VisitorRegisterStateVO;
import com.eastfair.imaster.vo.VisitorRegisterVO;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.projectcore.entity.Exhibition;
import com.eastfair.questionnaire.dto.AnswerSubjectResultSaveDTO;
import com.eastfair.questionnaire.dto.DisplayLocationQuestionnaireQuery;
import com.eastfair.questionnaire.vo.DynamicQuestionnaireVO;
import com.eastfair.security.formfield.ConvertByFormField;
import com.eastfair.tag.api.TagTargetBusinessServiceFeign;
import com.eastfair.tag.dto.TagTargetBusinessDTO;
import com.eastfair.tag.entity.TagTargetForExhibitorProduct;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.eastfair.core.exception.code.ExceptionCode.*;

/**
 * <p>
 * 业务实现类
 * 观众注册表（预登记表）
 * </p>
 *
 * @author zjn
 * @date 2021-08-18
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class VisitorRegisterServiceImpl extends SuperServiceImpl<VisitorRegisterMapper, VisitorRegister> implements VisitorRegisterService {

    @Autowired
    private ProjectCoreServiceFeign projectCoreServiceFeign;
    @Autowired
    private FormFieldServiceFeign formFieldServiceFeign;
    @Autowired
    private VisitorRegisterExceptionService visitorRegisterExceptionService;
    @Autowired
    private VisitorRegisterStateService visitorRegisterStateService;
    @Autowired
    private SwitchServiceFeign switchServiceFeign;
    @Autowired
    private RedisOps redisOps;
    @Autowired
    private VisitorUserService visitorUserService;
    @Autowired
    private VisitorRegisterPushService visitorRegisterPushService;
    @Autowired
    private QuestionnaireServiceFeign questionnaireServiceFeign;
    @Autowired
    private UserAccountServiceFeign userAccountServiceFeign;
    @Autowired
    private ConvertByFormField convertByFormField;

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(VisitorRegister entity) {
        UpdateWrapper<VisitorRegister> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(VisitorRegister::getProjectId, ContextUtil.getProjectId()).eq(VisitorRegister::getId, entity.getId());
        entity.setProjectId(null);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    @Override
    protected R<Boolean> handlerSave(VisitorRegister model) {
        //雪花ID
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    public R<List<FormFieldVO>> getFormField(VisitorRegisterDTO visitorRegisterDTO) {
        LanguageTypeEnum systemLanguage = LanguageTypeEnum.parse(ContextUtil.getLanguageType());
        FormFieldDTO formFieldDTO = FormFieldDTO.builder()
                .isDeleted(BusinessConstant.DELETE_NO).isEnabled(BusinessConstant.ENABLE_YES)
                .subjectType(SubjectTypeEnum.VISITOR.name())
                .isPerfectInfo(BusinessConstant.YES)
                .exhibitionId(ContextUtil.getExhibitionId())
                .languageType(LanguageTypeEnum.parse(visitorRegisterDTO.getLanguageType()).name()).build();
        R<List<FormFieldVO>> result = formFieldServiceFeign.getBySubjectType(formFieldDTO);
        if (LanguageTypeEnum.EN.eq(systemLanguage)) {
            ConvertUtil.convertByLanguageType(result.getData(), systemLanguage, true);
        }
        return result;
    }

    @Override
    public R<List<FormFieldVO>> getFormFieldByUserLanguage(VisitorRegisterDTO visitorRegisterDTO) {
        FormFieldDTO formFieldDTO = FormFieldDTO.builder()
                .isDeleted(BusinessConstant.DELETE_NO).isEnabled(BusinessConstant.ENABLE_YES)
                .subjectType(SubjectTypeEnum.VISITOR.name())
                .isPerfectInfo(BusinessConstant.YES)
                .exhibitionId(ContextUtil.getExhibitionId())
                .languageType(LanguageTypeEnum.parseByCountry(visitorRegisterDTO.getCountryId()).name()).build();
        return formFieldServiceFeign.getBySubjectType(formFieldDTO);
    }

    @Override
    @GlobalTransactional(name = "addVisitor", rollbackFor = Exception.class)
    public R<Long> addVisitor(VisitorRegisterDTO visitorRegisterDTO, SystemSourceEnum source, VisitorRegisterStateRegisterTypeEnum registerType) {
        visitorRegisterDTO.setExhibitionId(ContextUtil.getExhibitionId());

        //校验账号信息
        R result = checkUserAccountInfo(visitorRegisterDTO);
        if (!result.getIsSuccess()) {
            return result;
        }

        //校验表单信息
        result = checkFormFieldInfo(visitorRegisterDTO);
        if (!result.getIsSuccess()) {
            return result;
        }

        //预登记数据入库
        VisitorRegister visitorRegister = BeanUtil.copyProperties(visitorRegisterDTO, VisitorRegister.class);
        visitorRegister.setUserAccountId(ContextUtil.getUserId());
        save(visitorRegister);

        //预登记相关状态记录
        saveDefaultState(visitorRegisterDTO, visitorRegister.getId(), source, registerType);

        // 同步组织角色 注册成为观众
        UserAccountDto userAccountDto = new UserAccountDto();
        userAccountDto.setId(ContextUtil.getUserId());
        userAccountDto.setIsVisitor(BusinessConstant.YES);
        userAccountDto.setIsCompleteInfo(BusinessConstant.YES);
        userAccountServiceFeign.initRole(userAccountDto);

        return R.success(visitorRegister.getId());
    }

    @Override
    public R<DynamicQuestionnaireVO> getVisitorRegisterQuestionnaire() {
        // 获取当前观众信息
        VisitorRegisterVO visitorRegisterVO = getByUserAccountId().getData();
        if (Objects.isNull(visitorRegisterVO)) {
            return R.fail(VISITOR_NULL);
        }

        DisplayLocationQuestionnaireQuery displayLocationQuestionnaireQuery = new DisplayLocationQuestionnaireQuery();
        displayLocationQuestionnaireQuery.setSubjectType(SubjectTypeEnum.VISITOR.name());
        displayLocationQuestionnaireQuery.setSubjectId(visitorRegisterVO.getId());
        if (LanguageTypeEnum.EN.eq(LanguageTypeEnum.parseByCountry(visitorRegisterVO.getCountryId()))) {
            displayLocationQuestionnaireQuery.setDisplayLocation(DisplayLocationEnum.QUESTIONNAIRE_VISITOR_REGISTER_EN.name());
        } else {
            displayLocationQuestionnaireQuery.setDisplayLocation(DisplayLocationEnum.QUESTIONNAIRE_VISITOR_REGISTER_CN.name());
        }
        R<DynamicQuestionnaireVO> result = questionnaireServiceFeign.getQuestionnaireByDisplayLocation(displayLocationQuestionnaireQuery);
        if (result.getIsSuccess() && LanguageTypeEnum.EN.eq(LanguageTypeEnum.parse(ContextUtil.getLanguageType()))) {
            ConvertUtil.convertByLanguageType(result.getData(), LanguageTypeEnum.EN, true);
        }
        return result;
    }

    @Override
    @GlobalTransactional(name = "saveAnswerSubjectResult", rollbackFor = Exception.class)
    public R<String> saveAnswerSubjectResult(AnswerSubjectResultSaveDTO answerSubjectResultSaveDTO) {
        // 获取当前观众信息
        VisitorRegisterVO visitorRegisterVO = getByUserAccountId().getData();
        if (Objects.isNull(visitorRegisterVO)) {
            return R.fail(VISITOR_NULL);
        }

        // 保存问卷
        answerSubjectResultSaveDTO.setSubjectType(SubjectTypeEnum.VISITOR.name())
                .setSourceSystem(SystemSourceEnum.IMASTER.name())
                .setSubjectId(visitorRegisterVO.getId());
        questionnaireServiceFeign.save(answerSubjectResultSaveDTO);

        // 预登记审核状态
        AuditStateEnum auditState = getAuditState(visitorRegisterVO.getCountryId());

        // 获取观众预登记状态
        VisitorRegisterStateVO visitorRegisterStateVO = visitorRegisterStateService.getByVisitorRegisterId(visitorRegisterVO.getId());
        VisitorRegisterStateDTO visitorRegisterStateDTO = BeanUtil.copyProperties(visitorRegisterStateVO, VisitorRegisterStateDTO.class);
        visitorRegisterStateDTO.setAuditState(auditState.name());
        // 同步展立方
        VisitorRegisterDTO visitorRegisterDTO = BeanUtil.copyProperties(visitorRegisterVO, VisitorRegisterDTO.class);
        visitorRegisterPushService.pushVisitor(visitorRegisterDTO, visitorRegisterStateDTO, answerSubjectResultSaveDTO);

        // 观众表
        visitorUserService.saveVisitorUser(visitorRegisterDTO, visitorRegisterStateDTO);

        // 同步组织角色 注册成为观众
        UserAccountDto userAccountDto = new UserAccountDto();
        userAccountDto.setId(ContextUtil.getUserId());
        userAccountDto.setIsVisitor(BusinessConstant.YES);
        userAccountDto.setIsCompleteQuestion(BusinessConstant.YES);
        return R.success(visitorRegisterStateVO.getCardNumber());
    }

    @Override
    @GlobalTransactional(name = "saveAnswerSubjectResultBaoLi", rollbackFor = Exception.class)
    public R<String> saveAnswerSubjectResultBaoLi(AnswerSubjectResultSaveDTO answerSubjectResultSaveDTO) {
        // 获取当前观众信息
        VisitorRegisterVO visitorRegisterVO = getByUserAccountId().getData();
        if (Objects.isNull(visitorRegisterVO)) {
            return R.fail(VISITOR_NULL);
        }

        // 保存问卷
        answerSubjectResultSaveDTO.setSubjectType(SubjectTypeEnum.VISITOR.name())
                .setSourceSystem(SystemSourceEnum.IMASTER.name())
                .setSubjectId(visitorRegisterVO.getId());
        questionnaireServiceFeign.save(answerSubjectResultSaveDTO);

        // 生成胸牌卡号
        String cardNumber = getCardNumber(LanguageTypeEnum.parseByCountry(visitorRegisterVO.getCountryId()), ContextUtil.getExhibitionId());

        // 预登记审核状态
        AuditStateEnum auditState = getAuditState(visitorRegisterVO.getCountryId());

        // 获取观众预登记状态
        VisitorRegisterStateVO visitorRegisterStateVO = visitorRegisterStateService.getByVisitorRegisterId(visitorRegisterVO.getId());
        visitorRegisterStateVO.setCardNumber(cardNumber);
        visitorRegisterStateVO.setAuditState(auditState.getCode());
        visitorRegisterStateVO.setAuditTime(LocalDateTime.now());
        VisitorRegisterStateDTO visitorRegisterStateDTO = BeanUtil.copyProperties(visitorRegisterStateVO, VisitorRegisterStateDTO.class);
        visitorRegisterStateService.updateById(visitorRegisterStateDTO);

        // 同步展立方
        VisitorRegisterDTO visitorRegisterDTO = BeanUtil.copyProperties(visitorRegisterVO, VisitorRegisterDTO.class);
        visitorRegisterPushService.pushVisitorBaoLi(visitorRegisterDTO, visitorRegisterStateDTO, null, answerSubjectResultSaveDTO);

        // 观众表
        visitorUserService.saveVisitorUser(visitorRegisterDTO, visitorRegisterStateDTO);

        // 同步组织角色 注册成为观众
        UserAccountDto userAccountDto = new UserAccountDto();
        userAccountDto.setId(ContextUtil.getUserId());
        userAccountDto.setIsVisitor(BusinessConstant.YES);
        userAccountServiceFeign.initRole(userAccountDto);
        return R.success(visitorRegisterStateVO.getCardNumber());
    }

    @Override
    public R<VisitorRegisterVO> getByUserAccountId() {
        QueryWrapper<VisitorRegister> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(VisitorRegister::getProjectId, ContextUtil.getProjectId())
                .eq(VisitorRegister::getExhibitionId, ContextUtil.getExhibitionId())
                .eq(VisitorRegister::getUserAccountId, ContextUtil.getUserId())
                .eq(VisitorRegister::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(VisitorRegister::getIsEnabled, BusinessConstant.ENABLE_YES);
        return R.success(BeanUtil.copyProperties(getOne(queryWrapper, true), VisitorRegisterVO.class));
    }

    @Override
    public R<Boolean> getFaceIdentify(VisitorRegisterDTO visitorRegisterDTO) {
        Exhibition exhibition = projectCoreServiceFeign.getExhibitionById(ContextUtil.getExhibitionId()).getData();
        if (!StringUtils.isBlank(exhibition.getExhId())) {
            return R.success(FaceIdentifyUtils.sendPersonJoinFaceIdentify(exhibition.getExhId(), visitorRegisterDTO.getFaceImageUrl()));
        }
        return R.success(Boolean.FALSE);
    }

    /**
     * 校验账号信息
     *
     * @param visitorRegisterDTO 观众预登记数据
     * @return 校验结果信息
     */
    private R checkUserAccountInfo(VisitorRegisterDTO visitorRegisterDTO) {
        UserAccount userAccount = userAccountServiceFeign.get(ContextUtil.getUserId()).getData();
        if (userAccount == null) {
            return R.fail(USER_NO_ERROR);
        }

        //校验手机号
        if (StringUtil.isNotBlank(visitorRegisterDTO.getMobile())) {
            if (StringUtil.isNotBlank(userAccount.getMobile())) {
                if (!visitorRegisterDTO.getMobile().equals(userAccount.getMobile())) {
                    return R.fail(VISITOR_MOBILE_ERROR);
                }
            } else {
                UserAccount completeUserAccount = UserAccount.builder().id(userAccount.getId()).mobile(visitorRegisterDTO.getMobile()).build();
                UserAccountDto userAccountDto = new UserAccountDto();
                BeanUtils.copyProperties(completeUserAccount,userAccountDto);
                userAccountServiceFeign.updateById(userAccountDto);
            }
        }

        //校验邮箱
        if (StringUtil.isNotBlank(visitorRegisterDTO.getEmail())) {
            if (StringUtil.isNotBlank(userAccount.getEmail())) {
                if (!visitorRegisterDTO.getMobile().equals(userAccount.getMobile())) {
                    return R.fail(VISITOR_EMAIL_ERROR);
                }
            } else {
                UserAccount completeUserAccount = UserAccount.builder().id(userAccount.getId()).email(visitorRegisterDTO.getEmail()).build();
                UserAccountDto userAccountDto = new UserAccountDto();
                BeanUtils.copyProperties(completeUserAccount,userAccountDto);
                userAccountServiceFeign.updateById(userAccountDto);
            }
        }
        return R.success();
    }

    /**
     * 校验表单信息
     *
     * @param visitorRegisterDTO 观众预登记数据
     * @return 校验结果信息
     */
    private R checkFormFieldInfo(VisitorRegisterDTO visitorRegisterDTO) {
        FormFieldDTO formFieldDTO = FormFieldDTO.builder()
                .subjectType(SubjectTypeEnum.VISITOR.name())
                .isPerfectInfo(BusinessConstant.YES)
                .exhibitionId(ContextUtil.getExhibitionId())
                .languageType(LanguageTypeEnum.parseByCountry(visitorRegisterDTO.getCountryId()).name())
                .isEnabled(BusinessConstant.ENABLE_YES).isDeleted(BusinessConstant.DELETE_NO).build();
        // 表单校验
        FormFieldCheckDTO formFieldCheckDTO = FormFieldCheckDTO.builder().object(visitorRegisterDTO)
                .className(visitorRegisterDTO.getClass().getName()).formFieldDTO(formFieldDTO).build();
        Boolean flag = formFieldServiceFeign.checkFormFieldInfo(formFieldCheckDTO).getData();
        if (flag) {
            return R.success();
        }
        return R.fail(VISITOR_INFO_ERROR);
    }

    /**
     * 异常信息记录
     *
     * @param visitorRegisterDTO 预登记信息
     * @param systemSourceEnum   预登记来源
     */
    private void saveVisitorRegisterException(VisitorRegisterDTO visitorRegisterDTO, SystemSourceEnum systemSourceEnum) {
        // 本系统来源无需记录
        if (SystemSourceEnum.IMASTER.eq(systemSourceEnum)) {
            return;
        }

        // 保存异常记录
        VisitorRegisterException visitorRegisterException = BeanUtil.copyProperties(visitorRegisterDTO, VisitorRegisterException.class);
        visitorRegisterException.setSource(systemSourceEnum.name());
        visitorRegisterExceptionService.save(visitorRegisterException);
    }

    /**
     * 预登记初始化状态保存
     *
     * @param visitorRegisterDTO 预登记信息
     * @param visitorRegisterId  预登记信息id
     * @param source             预登记来源
     * @param registerType       注册方式
     */
    private void saveDefaultState(VisitorRegisterDTO visitorRegisterDTO, Long visitorRegisterId, SystemSourceEnum source, VisitorRegisterStateRegisterTypeEnum registerType) {
        // 预登记审核状态
        AuditStateEnum auditState = getAuditState(visitorRegisterDTO.getCountryId());

        // 保存预登记状态信息
        VisitorRegisterState visitorRegisterState = VisitorRegisterState.builder().projectId(ContextUtil.getProjectId())
                .exhibitionId(ContextUtil.getExhibitionId()).userAccountId(ContextUtil.getUserId()).visitorRegisterId(visitorRegisterId)
                .source(source.name()).auditState(auditState.name()).auditTime(LocalDateTime.now()).registerType(registerType)
                .isOffline(visitorRegisterDTO.getIsOffline()).isCompleteInfo(BusinessConstant.YES)
                .terminalType(ContextUtil.getTerminalType()).terminalDevice(ContextUtil.getTerminalDevice()).build();
        visitorRegisterStateService.save(visitorRegisterState);
    }

    /**
     * 根据用户语言获、预登记审核开关 获取观众审核状态
     *
     * @param countryId 用户国家
     * @return 预登记审核状态
     */
    private AuditStateEnum getAuditState(Integer countryId) {
        Switch auditStateSwitch = Switch.builder().subjectType(SubjectTypeEnum.VISITOR.name()).languageType(LanguageTypeEnum.CN.name()).build();
        if (LanguageTypeEnum.CN.eq(LanguageTypeEnum.parseByCountry(countryId))) {
            auditStateSwitch.setKeyword(SwitchEnum.VISITOR_REGISTER_AUDIT_CN.getCode());
        } else {
            auditStateSwitch.setKeyword(SwitchEnum.VISITOR_REGISTER_AUDIT_EN.getCode());
        }
        auditStateSwitch = switchServiceFeign.getByEntity(auditStateSwitch).getData();

        AuditStateEnum auditState;
        if (Objects.isNull(auditStateSwitch) || BusinessConstant.NO == auditStateSwitch.getStatus()) {
            auditState = AuditStateEnum.APPROVE;
        } else {
            auditState = AuditStateEnum.PENDING;
        }
        return auditState;
    }

    /**
     * 获取胸牌卡号
     *
     * @param languageType 用户语言
     * @param exhibitionId 展会id
     * @return 胸牌卡号
     */
    private String getCardNumber(LanguageTypeEnum languageType, Long exhibitionId) {
        String key = String.format(RedisKeyConstant.VISITOR_CARD_NUMBER, languageType.name().toLowerCase(), exhibitionId);
        return String.valueOf(redisOps.getValueOps().increment(key));
    }

    @Resource
    private TagTargetBusinessServiceFeign tagTargetBusinessServiceFeign;

    @Override
    public void testTag() {
        TagTargetForExhibitorProduct tagTargetForExhibitorProduct = new TagTargetForExhibitorProduct();
        tagTargetForExhibitorProduct.setSubjectType(SubjectTypeEnum.EXHIBITOR_PRODUCT);
        tagTargetForExhibitorProduct.setSubjectId(11112222L);
        tagTargetForExhibitorProduct.setName("展品222");
        tagTargetForExhibitorProduct.setEnName("test222");
        List<Long> tagIdList = new ArrayList<>();
        tagIdList.add(1610450008312119296L);
        tagIdList.add(1610468631290839040L);
        tagIdList.add(1631652612626452480L);
        tagTargetForExhibitorProduct.setTagIdList(tagIdList);

//        List<TagResourceDTO> tagResourceDTOList = new ArrayList<>();
//        TagResourceDTO tagResourceDTO = new TagResourceDTO();
//        tagResourceDTO.setResourceType(TagResourceTypeEnum.QUESTION_ANSWER);
//        tagResourceDTO.setResourceId(1111111111L);
//        tagResourceDTOList.add(tagResourceDTO);
//        tagTargetForExhibitorProduct.setTagResourceDTOList(tagResourceDTOList);


        TagTargetBusinessDTO<TagTargetForExhibitorProduct> tagTargetBusinessDTO = new TagTargetBusinessDTO();
        tagTargetBusinessDTO.setT(tagTargetForExhibitorProduct);
        tagTargetBusinessDTO.setClazz(TagTargetForExhibitorProduct.class);
        tagTargetBusinessServiceFeign.saveTagTarget(tagTargetBusinessDTO);

        System.out.println("11111");
    }

}